package com.rslai.base.tool.servertest.paramfilter;

import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;

public abstract class AbstractDateParamFilter extends ParamFilter {
    private Clock clock;

    public AbstractDateParamFilter(Clock clock) {
        this.clock = clock;
    }

    protected abstract Pattern getPattern();

    protected String doHandle(String param) {
        String result = param;
        Matcher matcher = getPattern().matcher(param);
        while (matcher.find()) {
            String group1 = matcher.group(1);
            String diff = StringUtils.trim(group1);
            if ((StringUtils.isNotBlank(diff)) && (diff.startsWith("+"))) {
                diff = diff.substring(1);
            }

            String group2 = matcher.group(2);
            String formatExpression = StringUtils.trim(group2);

            String group3 = matcher.group(3);
            Step step = getStep(group3);

            Integer i = Integer.valueOf(diff);
            Date date = step.diff(i);

            String formatDate = format(param, formatExpression, date);
            result = postProcess(result, group1, group2, group3, formatDate);
        }
        return result;
    }

    protected abstract String postProcess(String paramString1, String paramString2, String paramString3, String paramString4, String paramString5);

    protected abstract String format(String paramString1, String paramString2, Date paramDate);

    protected Step getStep(String step) {
        step = StringUtils.trim(step);
        if (StringUtils.isBlank(step)) {
            return new DayStep();
        }
        switch (step.charAt(0)) {
            case 'Y':
            case 'y':
                return new YearStep();
            case 'M':
                return new MonthStep();
            case 'D':
            case 'd':
                return new DayStep();
            case 'H':
            case 'h':
                return new HourStep();
            case 'm':
                return new MinuteStep();
            case 'S':
            case 's':
                return new SecondsStep();
        }
        return new DayStep();
    }

    protected boolean support(String param) {
        return (!StringUtils.isBlank(param)) && (getPattern().matcher(param).find());
    }

    private class SecondsStep extends AbstractDateParamFilter.Step {
        private SecondsStep() {
            super();
        }

        public Date diff(Integer i) {
            return DateUtils.addSeconds(AbstractDateParamFilter.this.clock.current(), i.intValue());
        }

    }

    private class MinuteStep extends AbstractDateParamFilter.Step {
        private MinuteStep() {
            super();
        }

        public Date diff(Integer i) {
            return DateUtils.addMinutes(AbstractDateParamFilter.this.clock.current(), i.intValue());
        }

    }

    private class HourStep extends AbstractDateParamFilter.Step {
        private HourStep() {
            super();
        }

        public Date diff(Integer i) {
            return DateUtils.addHours(AbstractDateParamFilter.this.clock.current(), i.intValue());
        }

    }

    private class MonthStep extends AbstractDateParamFilter.Step {
        private MonthStep() {
            super();
        }

        public Date diff(Integer i) {
            return DateUtils.addMonths(AbstractDateParamFilter.this.clock.current(), i.intValue());
        }

    }

    private class YearStep extends AbstractDateParamFilter.Step {
        private YearStep() {
            super();
        }

        public Date diff(Integer i) {
            return DateUtils.addYears(AbstractDateParamFilter.this.clock.current(), i.intValue());
        }

    }

    private class DayStep extends AbstractDateParamFilter.Step {
        private DayStep() {
            super();
        }

        public Date diff(Integer i) {
            return DateUtils.addDays(AbstractDateParamFilter.this.clock.current(), i.intValue());
        }

    }

    protected abstract class Step {
        protected Step() {
        }

        public abstract Date diff(Integer paramInteger);
    }
}

